#ifndef ANALYSISCONFIG_H
#define ANALYSISCONFIG_H

#include <map>
#include <string>
#include <iostream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include "HistogramConfig.h"
#include "AnalysisResult.h"

using namespace std;

class AnalysisConfig {
    private:
        map <string,string> config;
    public:
        /** Tak zdecydowanie nie powinno pozostać, że te wektory są publiczne, póki co to jest wygodne */
        vector <HistogramConfig> probeBgdTempl, selectedBgdTempl, probeSigTempl, selectedSigTempl;
        HistogramConfig dataProbe, dataSelected;
        /** The default constructor.
         * It is possible to assign default configuration values here to any parameters,
         * although it would probably be cleaner to do this in the get* functions */
        AnalysisConfig() {
            config["verifyError"]="0";
            config["fillEmptyBins"]="0";
            config["flatten"]="0";
            config["saveHistograms"]="1";
            config["efficTestCount"]="20";
        }
        AnalysisConfig(map <string,string> & c) {
            config=c;
        }
        void append(const AnalysisConfig & conf) {
            config.insert(conf.config.begin(),conf.config.end());
        }
        /** This function adds two AnalysisConfigs together. The previous one has precedence, i.e. if both the object and the argument
         * have differerent values for a key, the result contains the value of the object 
         * @param The configuration to be added.
         * @return The sum of the configuration and this object's configuration, with this object's configuration taking precedence.
         * */
        AnalysisConfig add(const AnalysisConfig & conf) {
            AnalysisConfig temp = *this;
            temp.append(conf);
            return temp;
        }
        void print() const {
            cout << "Analysis Configuration:" << endl;
            for(map <string,string>::const_iterator it = config.begin();it!=config.end();it++) {
                cout << (*it).first << " -> " << (*it).second << endl;
            }
        }
        void setParameter(string param, string value) {
            config[param]=value;
        }
        string getParameter(const string & param) {
            return config[param];
        }
        void dump(AnalysisResult & result) {
            result.setVersion(getVersion());
            result.setIsData(getIsData());
            result.setMethod(getMethod());
            result.setEfficCalcMethod(getEfficCalcMethod());
            result.setETAMin(getETAMin());
            result.setETAMax(getETAMax());
            
            for(int i = 1;i<=getBgdProbeTemplNumber();i++) {
                try {
                    result.setBgdProbeTemplate(i,getBgdProbeTemplate(i));
                } catch (...) {break;}
            }
            for(int i = 1;i<=getBgdSelectedTemplNumber();i++) {
                try {
                    result.setBgdSelectedTemplate(i,getBgdSelectedTemplate(i));
                } catch (...) {break;}
            }
            for(int i = 1;i<=getSigProbeTemplNumber();i++) {
                try {
                    result.setSigProbeTemplate(i,getSigProbeTemplate(i));
                } catch (...) {break;}
            }
            for(int i = 1;i<=getSigSelectedTemplNumber();i++) {
                try {
                    result.setSigSelectedTemplate(i,getSigSelectedTemplate(i));
                } catch (...) {break;}
            }
            result.setSigTemplFileName(getSigTemplFileName());
            result.setBgdTemplFileName(getBgdTemplFileName());
            result.setDataFileName(getDataFileName());
            result.setMCTemplFileName(getMCTemplFileName());
            result.setDataProbe(getDataProbe());
            result.setDataSelected(getDataSelected());
        }
        int getVersion() {
            return boost::lexical_cast<int>( config["version"] );
        }
        bool getIsData() {
            return boost::lexical_cast<bool>( config["isData"] );
        }
        int getMethod() {
            return boost::lexical_cast<int>( config["method"] );
        }
        int getETAMin() {
            return boost::lexical_cast<int>( config["ETAMin"] );
        }
        int getETAMax() {
            return boost::lexical_cast<int>( config["ETAMax"] );
        }
        int getBgdProbeTemplate(int num) {
            return boost::lexical_cast<int>( config["bgdprobe"+boost::lexical_cast<string>(num)] );
        }
        int getSigProbeTemplate(int num) {
            return boost::lexical_cast<int>( config["sigprobe"+boost::lexical_cast<string>(num)] );
        }
        int getBgdSelectedTemplate(int num) {
            return boost::lexical_cast<int>( config["bgdselected"+boost::lexical_cast<string>(num)] );
        }
        int getSigSelectedTemplate(int num) {
            return boost::lexical_cast<int>( config["sigselected"+boost::lexical_cast<string>(num)] );
        }
        string getSigTemplFileName() {
            return config[string("sigTemplFileName")];
        }
        string getBgdTemplFileName() {
            return config[string("bgdTemplFileName")];
        }
        string getDataFileName() {
            return config[string("dataFileName")];
        }
        string getMCTemplFileName() {
            return config[string("MCFileName")];
        }
        vector <HistogramConfig> getProbeBgdTempl() {
            return probeBgdTempl;
        }
        vector <HistogramConfig> getSelectedBgdTempl() {
            return selectedBgdTempl;
        }
        vector <HistogramConfig> getProbeSigTempl() {
            return probeSigTempl;
        }
        vector <HistogramConfig> getSelectedSigTempl() {
            return selectedSigTempl;
        }
        HistogramConfig getProbeDataTempl() {
            return dataProbe;
        }
        HistogramConfig getSelectedDataTempl() {
            return dataSelected;
        }
        bool getIsMethodRaw() {
            return getMethod()==1;
        }
        bool getIsMethodSubtraction() {
            return getMethod()==2;
        }
        bool getIsMethodEXLL() {
            return getMethod()==3;
        }
        bool getIsMethodCHI2() {
            return getMethod()==4;
        }
        bool getIsMethodBinomialSubtraction() {
            return getEfficCalcMethod()==1;
        }
        bool getIsMethodFromFit() {
            return getEfficCalcMethod()==2;
        }
        bool getIsMethodDirect() {
            return getEfficCalcMethod()==3;
        }
        bool getIsMethodIndirect() {
            return getEfficCalcMethod()==4;
        }
        int getETMax() {
            return boost::lexical_cast<int>( config["ETMax"] );
        }
        int getETMin() {
            return boost::lexical_cast<int>( config["ETMin"] );
        }
        int getIsolThr() {
            return int(boost::lexical_cast<double>( config["isolThr"] )*100+0.5);
        }
        int getEfficCalcMethod() {
            return boost::lexical_cast<int>( config["efficCalcMethod"] );
        }
        int getEfficTestCount() {
            return boost::lexical_cast<int>( config["efficTestCount"] );
        }
        bool getFlatten() {
            return boost::lexical_cast<bool>( config["flatten"] );
        }
        bool getFillEmptyBins() {
            return boost::lexical_cast<bool>( config["fillEmptyBins"] );
        }
        bool getVerifyError() {
            return boost::lexical_cast<bool>( config["verifyError"] );
        }
        bool getIsSaveHistograms() {
            return boost::lexical_cast<bool>( config["saveHistograms"] );
        }
        int getDataProbe() {
            return boost::lexical_cast<int>( config["dataprobe"] );
        }
        int getDataSelected() {
            return boost::lexical_cast<int>( config["dataselected"] );
        }
        int getSigProbeTemplNumber() {
            return boost::lexical_cast<int>( config["numSigProbeTempl"] );
        }
        int getBgdProbeTemplNumber() {
            return boost::lexical_cast<int>( config["numBgdProbeTempl"] );
        }
        int getSigSelectedTemplNumber() {
            return boost::lexical_cast<int>( config["numSigSelectedTempl"] );
        }
        int getBgdSelectedTemplNumber() {
            return boost::lexical_cast<int>( config["numBgdSelectedTempl"] );
        }
        string getTag() {
            return config["tag"];
        }
};

#endif
